#ifndef CASEDB_STATEMENT_HPP
#define CASEDB_STATEMENT_HPP

#include "CaseDB/Parameter.hpp"
#include <list>

namespace CaseDB
{

/// @ingroup CaseDB
/// @brief It describes an SQL statement to be executed.
/// 
/// The statement description contains the list of parameters (using parameter metadata). If the statement is a 
///	query, the resulted record set is stored separately. However, the output parameter values will be stored in the 
///	parameter list after statement execution.
/// @par
/// The statement can contain placeholders for parameters (marked with ? in the statement). The parameter binding is 
///	made in the order the parameters are specified in the parameter list. So when setting up the statement, make sure 
///	the parameter descriptions are in the right order, to correspond with the desired placeholders.
/// @sa CaseDB::Connection::execute( Statement& statement)
/// @sa CaseDB::Connection::execute( Statement& statement, RecordSet& results)
class CASEDB_API Statement
{
	typedef std::list< Parameter> ParamCollection;
public:
	/// @brief The iterator to be used for parameters.
	typedef ParamCollection::const_iterator ConstParamIterator;
	/// @brief The iterator to be used for parameters.
	typedef ParamCollection::iterator ParamIterator;

public:
	/// @brief It initializes the statement.
	/// @param statement the database statement to be executed.
	Statement( const std::string& statement);

	/// @brief It adds a parameter to the list of parameters.
	/// @param param the parameter to be added.
	void addParameter( const Parameter& param);

	/// @brief It adds an input or input-output parameter.
	/// @param dbType the type of the value bound to the parameter.
	/// @param direction the direction of the parameter.
	/// @param value the input value of the parameter to be bound in the statement.
	void addParameter( DbTypes dbType, ParamDirections direction, const boost::any& value);

	/// @brief It adds an input or input-output parameter of type integer.
	/// @param value the input value to be bound to the parameter
	/// @param direct the direction of the parameter.
	void addParameter( int value, ParamDirections direction = ParamDirectionsEnum::In);

	/// @brief It adds an input or input-output parameter of type string.
	/// @param value the input value to be bound to the parameter
	/// @param direct the direction of the parameter.
	void addParameter( const std::string& value, ParamDirections direction = ParamDirectionsEnum::In);

	/// @brief It adds an input or input-output parameter of type floating point.
	/// @param value the input value to be bound to the parameter
	/// @param direct the direction of the parameter.
	void addParameter( double value, ParamDirections direction = ParamDirectionsEnum::In);

	/// @brief It adds an input parameter.
	/// @param dbType the type of the value bound to the parameter.
	/// @param value the input value of the parameter to be bound in the statement.
	void addParameter( DbTypes dbType, const boost::any& value);

	/// @brief It adds an output parameter.
	/// @param dbType the type of the value bound to the parameter.
	void addParameter( DbTypes dbType);

	/// @brief It gets an iterator to the first parameter in the list.
	/// @{
	ParamIterator paramsBegin() { return parameters_.begin(); }
	ConstParamIterator paramsBegin() const { return parameters_.begin(); }
	/// @}

	/// @brief It gets an iterator to the end of the parameter list.
	/// @{
	ParamIterator paramsEnd() { return parameters_.end(); }
	ConstParamIterator paramsEnd() const { return parameters_.end(); }
	/// @}

	/// @brief It gets the statement text to be executed.
	const std::string& statement() const { return statement_; }

private:
	std::list< Parameter> parameters_;
	std::string statement_;
};

} // namespace CaseDB

#endif // CASEDB_STATEMENT_HPP
